package com.smh.demo1.a22;

import com.smh.demo1.a22.pojo.User;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.*;

import java.util.List;

/**
 * @author shiminghui
 * @date 2025/5/2 18:01
 * @description: TODO
 */
public class A22 {
    public static void main(String[] args) throws Exception {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        // 生成测试请求
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setMethod("GET");
        request.setParameter("name", "smh");
        request.setParameter("age", "12");
        request.setParameter("birthDate", "2004-10-26 00:00:00");

        // 创建ServletInvocableHandlerMethod
        ServletInvocableHandlerMethod method = new ServletInvocableHandlerMethod(new Controller1(), Controller1.class.getMethod("test", User.class));


        // 设置参数绑定工厂
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
        initializer.setConversionService(conversionService);
        ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null, initializer);
        method.setDataBinderFactory(factory);

        // 设置参数解析器
        HandlerMethodArgumentResolverComposite resolverComposite = new HandlerMethodArgumentResolverComposite();
        // todo 添加自定义的参数解析器
        resolverComposite.addResolvers(
                //    beanFactory环境变量和配置文件里的数据都要从这里面读取    false 表示必须有 @RequestParam
                new RequestParamMethodArgumentResolver(beanFactory, false),
                // 路径参数解析器
                new PathVariableMethodArgumentResolver(),
                // 请求头解析器
                new RequestHeaderMethodArgumentResolver(beanFactory),
                // Cookie解析器
                new ServletCookieValueMethodArgumentResolver(beanFactory),
                // 表达式解析器 即@Value注解
                new ExpressionValueMethodArgumentResolver(beanFactory),
                // request, response, session ...解析器
                new ServletRequestMethodArgumentResolver(),
                new ServletModelAttributeMethodProcessor(false), // 必须有 @ModelAttribute
                // @RequestBody 解析器
                new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
                // 做一个保底操作, 有注解的优先处理没有的才会匹配这里,匹配成功再执行
                new ServletModelAttributeMethodProcessor(true), // 省略了 @ModelAttribute
                new RequestParamMethodArgumentResolver(beanFactory, true) // 省略 @RequestParam
        );
        method.setHandlerMethodArgumentResolvers(resolverComposite);

        // 设置一个默认的参数名解析器
        method.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());

        // 创建一个MavContainer
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();

        // 执行方法
        method.invokeAndHandle(new ServletWebRequest(request), mavContainer);

        // 打印MavContainer中的数据
        System.out.println(mavContainer.getModel());

        context.close();
    }
}
